<!-- https://map.geoq.cn/arcgis/rest/services/ChinaOnlineCommunity/MapServer
    "https://wl.arcgisonline.cn/server/rest/services/wl/hightf/FeatureServer/0",
-->




<html>

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    <title>SceneView - goTo() | Sample | ArcGIS API for JavaScript 4.20</title>

    <link rel="stylesheet" href="https://js.arcgis.com/4.20/esri/themes/light/main.css" />
    <script src="https://cdn.jsdelivr.net/npm/exif-js"></script>
    <script src="https://js.arcgis.com/4.20/"></script>
    <style>
        html,
        body,
        #viewDiv {
            padding: 0;
            margin: 0;
            height: 100%;
            width: 100%;
        }

        #optionsDiv {
            position: absolute;
            bottom: 17px;
            width: 100%;
            padding: 20px 0;
            z-index: 1;
            text-align: center;
        }

        button {
            background: white;
            padding: 7px;
            border: 1px solid #005e95;
            font-size: 0.9em;
            margin: 5px;
            color: #005e95;
        }

        button:hover {
            background: #005e95;
            color: white;
            cursor: pointer;
        }
    </style>

    <script>
        require(
            [
                "esri/Map",
                "esri/views/SceneView",
                "esri/layers/TileLayer",
                "esri/views/MapView",
                "esri/layers/FeatureLayer",
                "esri/core/promiseUtils",
                "esri/Graphic",
                "esri/geometry/Point",
                "esri/rest/locator"
            ], (
                Map,
                SceneView,
                TileLayer,
                MapView,
                FeatureLayer,
                promiseUtils,
                Graphic,
                Point,
                locator
            ) => {
            const map = new Map();
            const view = new SceneView({
                container: "viewDiv",
                map: map,
                zoom: 4
            });

            let dTlayer = new TileLayer({
                // url: "https://services.arcgisonline.com/arcgis/rest/services/World_Terrain_Base/MapServer"
                url: "https://map.geoq.cn/arcgis/rest/services/ChinaOnlineCommunity/MapServer",
            });
            map.add(dTlayer);

            view.on("click", e => {
                let { mapPoint: { x, y } } = e;
                console.log(e, [x, y]);
                // view.hitTest(e).then(event => {
                //     console.log(event);
                // });
            })

            view.when(() => {
                // 地图加载完成
                setTimeout(() => {
                    view.goTo({
                        position: {
                            // x: 121.42989101233015,
                            // y: 31.221434715924108,
                            // z: 10000,
                            x: 13516659.320133716,
                            y: 3660995.6037034923,
                            z: 100000,
                            spatialReference: {
                                // wkid: 4326
                                wkid: 102100
                            }
                        },
                        heading: 0,
                        tilt: 0,
                    },
                        {
                            duration: 3000,
                            easing: 'linear'
                        }
                        // 蹦跶几下？
                        /**
                         *  // Define your own function for the easing option
                         *      function customEasing(t) {
                         *         return 1 - Math.abs(Math.sin(-1.7 + t * 4.5 * Math.PI)) * Math.pow(0.5, t * 10);
                         *      }
                         */
                        // {
                        //     speedFactor: 0.3,
                        //     easing: customEasing
                        // }
                    ).catch(catchAbortError);
                }, 500);
            })
                .then(fetchImages)
                .then(getFeaturesFromPromises)
                .then(createLayer)
                .then(addToView)
                .catch((e) => {
                    console.error("Creating FeatureLayer from photos failed", e);
                });


            /**
             * Fetches a list of images and returns a list of promises
             */
            function fetchImages() {
                const numPhotos = 3;
                let points = [[13521037.853465399, 3649610.2371688695], [13514730.5482262, 3671112.349177918], [13542513.302425485, 3649579.8708908306]]
                const graphicPromises = [];
                const baseUrl = "https://arcgis.github.io/arcgis-samples-javascript/sample-data/featurelayer-collection/photo-";

                for (let i = 1; i <= numPhotos; i++) {
                    const url = baseUrl + i.toString() + ".jpg";
                    const graphicPromise = exifToGraphic(url, i, points[i - 1]);
                    graphicPromises.push(graphicPromise);
                }
                let aaa = promiseUtils.eachAlways(graphicPromises);
                return aaa;
            }

            // Filters only promises that resolve with valid values (a graphic
            // in this case) and resolves them as an array of graphics.
            // In other words, each attempt at fetching an image returns a promise.
            // Images that fail to fetch will be filtered out of the response array
            // so the images that successfully load can be added to the layer.
            function getFeaturesFromPromises(eachAlwaysResponses) {
                let bbb = eachAlwaysResponses.filter((graphicPromise) => {
                    return graphicPromise.value;
                }).map((graphicPromise) => {
                    return graphicPromise.value;
                });
                return bbb
            }

            //  Creates a client-side FeatureLayer from an array of graphics
            function createLayer(graphics) {
                return new FeatureLayer({
                    source: graphics,
                    objectIdField: "OBJECTID",
                    fields: [{
                        name: "OBJECTID",
                        type: "oid"
                    }, {
                        name: "url",
                        type: "string"
                    }],
                    popupTemplate: {
                        title: (event) => {
                            return locator
                                .locationToAddress({
                                    location: event.graphic.geometry
                                })
                                .then((response) => {
                                    return response.address;
                                }).catch((error) => {
                                    return "The middle of nowhere";
                                });
                        },
                        content: "<img src='{url}'>"
                    },
                    renderer: {
                        // type: "simple",
                        // symbol: {
                        //     type: "text",
                        //     color: "#7A003C",
                        //     text: "\ue661",
                        //     font: {
                        //         size: 20,
                        //         family: "CalciteWebCoreIcons"
                        //     }
                        // }


                        type: "simple",
                        symbol: {
                            type: "simple-marker",
                            size: 10,
                            color: "red",
                            outline: {
                                width: 0.5,
                                color: "black"
                            }
                        }
                    }
                });
            }

            // Adds a given layer to the map in the view
            function addToView(layer) {
                map.add(layer);
            }


            /**
             * Fetches and loads an image from a url and gets the latitude/longitude
             * GPS data from the EXIF data of the image. Returns a promise that
             * resolves to a Graphic with a point geometry representing the location
             * where the photo was taken.
             */
            function exifToGraphic(url, id, points) {
                return promiseUtils.create((resolve, reject) => {
                    const image = document.createElement("img");
                    image.src = url;
                    image.onload = () => {
                        image.load = image.onerror = null;
                        EXIF.getData(image, function () {

                            const latitude = EXIF.getTag(this, "GPSLatitude");
                            const latitudeDirection = EXIF.getTag(this, "GPSLatitudeRef");
                            const longitude = EXIF.getTag(this, "GPSLongitude");
                            const longitudeDirection = EXIF.getTag(this, "GPSLongitudeRef");

                            if (!latitude || !longitude) {
                                reject(new Error("Photo doesn't contain GPS information: ", this.src));
                                return;
                            }
                            const location = new Point({
                                // latitude: dmsDD(latitude, latitudeDirection),
                                // longitude: dmsDD(longitude, longitudeDirection)
                                x: points[0],
                                y: points[1],
                                spatialReference: {
                                    // wkid: 4326
                                    wkid: 102100
                                }
                            });
                            resolve(new Graphic({
                                geometry: location,
                                attributes: {
                                    url: url,
                                    OBJECTID: id,
                                    x: points[0],
                                    y: points[1],
                                    spatialReference: {
                                        // wkid: 4326
                                        wkid: 102100
                                    }
                                }
                            }));
                        });
                    };
                    image.onerror = () => {
                        image.load = image.onerror = null;
                        reject(new Error("Error while loading the image"));
                    }
                });
            }

            // Converts a DMS coordinate to decimal degrees
            function dmsDD([degrees, minutes, seconds], direction) {
                let dd = degrees + (minutes / 60) + (seconds / 3600);
                if (direction === "S" || direction === "W") {
                    dd *= -1;
                }
                return dd;
            }








            // -----------------------------------------------------------------




















            /*****************************************************************
             *
             * Add event listeners to go to a target point using animation options
             *
             *****************************************************************/

            // The target point is a new camera obtained by shifting the current camera 30 degrees to the east

            function shiftCamera(deg) {
                const camera = view.camera.clone();
                camera.position.longitude += deg;
                return camera;
            }

            function catchAbortError(error) {
                if (error.name != "AbortError") {
                    console.error(error);
                }
            }

            document.getElementById("default").addEventListener("click", () => {
                // Don't set any animation options for a default camera flight
                view.goTo(shiftCamera(60)).catch(catchAbortError);
            });

            document.getElementById("linearSlow").addEventListener("click", () => {
                view
                    .goTo(
                        shiftCamera(60),
                        // Animation options for a slow linear camera flight
                        {
                            speedFactor: 0.1,
                            easing: "linear"
                        }
                    )
                    .catch(catchAbortError);
            });

            document.getElementById("linearFast").addEventListener("click", () => {
                view
                    .goTo(
                        shiftCamera(60),
                        // Animation options for a fast linear camera flight
                        {
                            speedFactor: 6,
                            easing: "linear"
                        }
                    )
                    .catch(catchAbortError);
            });

            document.getElementById("expoIncrease").addEventListener("click", () => {
                view
                    .goTo(
                        shiftCamera(60),
                        // Animation options for a camera flight with an increasing speed
                        {
                            duration: 4000,
                            easing: "in-expo"
                        }
                    )
                    .catch(catchAbortError);
            });

            document.getElementById("fixedDuration").addEventListener("click", () => {
                view
                    .goTo(shiftCamera(30), {
                        duration: 10000,
                        maxDuration: 10000 // Make sure to set maxDuration if the duration is bigger than 8000 ms
                    })
                    .catch(catchAbortError);
            });



            document.getElementById("toPoint").addEventListener("click", () => {
                view.goTo({
                    position: {
                        // x: 121.42989101233015,
                        // y: 31.221434715924108,
                        x: 13515390.146474343,
                        y: 3660951.1180685167,
                        z: 3000,
                        spatialReference: {
                            // wkid: 4326
                            wkid: 102100
                        }
                    },
                    heading: 0,
                    tilt: 0
                },
                    {
                        duration: 1000,
                        easing: "linear"//"linear"|"in-cubic"|"out-cubic"|"in-out-cubic"|"in-expo"|"out-expo"|"in-out-expo"|"in-out-coast-quadratic"
                    }
                ).catch(catchAbortError);
            });
        });
    </script>
</head>

<body>
    <div id="optionsDiv">
        <button id="default">Default flight</button>
        <button id="linearSlow">Linear slow flight</button>
        <button id="linearFast">Linear fast flight</button>
        <button id="expoIncrease">Exponentially increasing speed flight</button>
        <button id="fixedDuration">10 seconds flight</button>
        <button id="toPoint">toPoint</button>
    </div>
    <div id="viewDiv"></div>
</body>

</html>